//
//  HQCapture11ViewController.m
//  精通Objective-C
//
//  Created by 花强 on 2017/12/21.
//  Copyright © 2017年 花强. All rights reserved.
//

#import "HQCapture11ViewController.h"
#import "C11NetConnector.h"

@interface HQCapture11ViewController ()

@end

@implementation HQCapture11ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    /*
     
     第11章 Foundation框架中的系统服务
     
     本章介绍提供系统服务的Foundation框架类；
        为网络、文件管理、进程间通信、系统信息检索、文本处理、线程和并发机制提供多种操作系统服务；
     
     11.1 网络服务
     Foundation框架含有各种支持网络服务的API；
        接下来介绍访问网络主机信息的API；
        以及利用Bonjour网络协议发布和发现网络服务的方式；
     
     11.1.1 NSHost类
     
     NSHost类含有多个用于访问网络主机信息的方法；
        网络主机信息：
            指连入网络的计算机和设备的网络名称和地址；
        一个NSHost对象代表一个独立的网络主机；
            使用该对象中的方法可以查找网络中计算机和其他设备的网络名称和地址信息；
     
     示例：
        我们使用NSHost对象中的currentHost和name方法，获取运行该程序的主机的名称；
     （Code）
     NSHost *myHost = [NSHost currentHost];
     NSLog(@"%@",[myHost name]);
     
        使用NSHost对象中的hostWithName：方法和address方法，通过域名创建对象；
     （Code）
     NSHost * appress = [NSHost hostWithName:@"www.apress.com"];
     NSLog(@"%@",[appress address]);
     
     注意：这是Mac OS上使用的类；
            我们新建了一个工程C11HostInfoProject用于尝试使用这些类；
     
     11.1.2 Bonjour网络服务
     
     Bonjour是一种协议；
        使用它可以自动创建可用的IP网络，而无需进行配置或手动干预；
        因此也被称为零配置网络；
     
     Bonjour专门用于使设备（如计算机和打印机）自动连接网络；
        他执行了各种函数，包括服务发现、地址分配和主机名解析；
     
     NSNetService类和NSNetServiceBrowser类提供了管理Bonjour网络服务的功能；
        NSNetService类：
            可以代表由应用发布或用作客户端的网络服务；
            服务可以是你编写的程序发布的本地服务，也可以是你编写的程序需要使用的远程服务；
        NSNetServiceBrowser类：
            用于寻找已经发布的网络服务；
        这两个类都必须通过委托对象完成方法调用；
            每个类中的方法都是以异步的方式被调用，而且在运行循环中被执行；
            （本章稍后会介绍使用NSRunLoop类管理运行循环的方法）
     
     11.2 应用服务
     
     应用服务中含有很多通用API，使用它们可以获取和设置与应用进程有关的信息；
     
     NSProcessInfo类：
        用于获取当前运行程序（即进程）的信息；
        使用类方法processInfo可以获取当前进程的NSProcessInfo对象；
        NSProcessInfo对象含有获取进程信息（如命令行参数、环境变量、主机名和进程名称等）的实例方法；
     （Code）
     */
     NSString * nameProcess = [[NSProcessInfo processInfo] processName];
     NSLog(@"nameProcess = %@",nameProcess);
     /*
     log:
     2017-12-22 14:12:16.780759+0800 精通Objective-C[1829:7270160] nameProcess = 精通Objective-C

     NSUserDefaults类：
        提供了管理用户首选项（user preferences）的API；
        这些信息用于配置应用程序，会永久存储在本地文件系统中；
        提供了首选项的应用程序使用户能够自定义该应用程序的行为；
      
     NSUserDefaults类既含有设置和获取首选项的方法，也含有管理首选项系统其它方面的方法；
        设置和获取首选项的方法支持原始数据类型和属性列表中类型的对象（即NSData、NSString、NSNumber、NSDate、NSArray和NSDictionary对象）；
        首选项以键值对形式存储在用户的默认数据库中；
     
     设置首选项、获取首选项：
      （Code）
     */
    NSUserDefaults * userDef = [NSUserDefaults standardUserDefaults];
    [userDef setObject:@"Flower" forKey:@"USER_DATA_NAME"];
    NSLog(@"%@",[userDef objectForKey:@"USER_DATA_NAME"]);
     /*
     log:
      2017-12-22 14:32:53.091750+0800 精通Objective-C[2035:7288558] Flower
     
     11.3 正则表达式和文本处理
      
     NSRegularExpression类：
        用于在字符串中处理正则表达式；
        正则表达式是一种设置和识别文本的模式；
        NSRegularExpression类含有创建和初始化NSRegularExpression对象的方法，以及执行各自正则表达式操作（寻找匹配项、匹配的数值等）的方法；
      
     Foundation框架中的NSOrthography、NSSpellServer和NSTextCheckingResult类主要用于处理文本；
        NSOrthography类：
            可用于描述文本的语言学内容（文本含有的脚本、脚本的主导语言和可能出现的其他语言、文本整体的主导脚本和语言）；
        NSSpellServer类：
            提供了一种机制，通过该机制可以使应用程序的拼写检查器为所有应用程序提供拼写服务；
            该类含有了用于配置拼写服务器的方法、提供拼写服务的方法和管理拼写检查进程的方法；
        NSTextCheckingResult类：
            用于描述被文本检查操作找到的项目；
            所有对象都代表在文本块分析过程中找到的请求文本；
      
      下述代码示例使用了NSRegularExpression对象，获取并显示了它的数据；
      （Code）
      */
    NSError * error;
    NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:@"world" options:NSRegularExpressionCaseInsensitive error:&error];//创建正则表达式
    NSString * greeting = @"Hello, world!";
    NSTextCheckingResult * match = [regex firstMatchInString:greeting options:0 range:NSMakeRange(0, [greeting length])];//获取正则表达式的查询结果
    NSRange range = [match range];
    NSLog(@"Match begins at %ldth character in string",range.location);
     /*
     log:
      2017-12-22 16:03:01.259091+0800 精通Objective-C[2869:7362601] Match begins at 7th character in string

     11.4 文件系统实用程序
      
     文件I/O类中含有许多用于使用文件和目录的API；
        使用这些类可以显示文件路径；
        对文件和目录执行基本操作；
        查询系统中的目录；
        以及使用数据流对文件、内存和网络资源执行输入/输出（I/O）操作；
      
     11.4.1 应用程序包
      
     NSBundle类：
        可以容纳程序中使用的代码和资源；
        使用这些类可以定位程序资源、以动态方式加载和卸载可执行代码以及协助进行本地化；
      
     NSBundle类含有很多方法：
        使用这些方法可以创建和初始化包、获取包对象和包类、加载包中的代码、寻找包中的资源、获取包中的信息和管理本地化；
      
     第7、9章介绍了可选包，以及如何使用NSBundle类动态加载包和通过包类创建对象，可参考部分内容；
      
     11.4.2 文件管理
    
     NSFileHandle类：
        提供了底层文件 管理 实用程序；
        一个NSFileHandle类实例就是一个文件描述符的面向对象封装器；
        该类含有多个方法：
            使用它们可以创建和初始化文件句柄、获取文件描述符、使用文件句柄执行文件I/O操作以及关闭文件；
        NSFileHandle类还支持异步文件操作；
        使用该类中的许多创建犯法还可以得到文件描述符的所有权，而且会在释放对象后自动关闭文件；
        NSFileHandle类还含有多个通过输入文件描述符创建NSFileHandle对象的方法；
            在这种情况，可以使用closeFile方法关闭描述符；
      
     使用NSFileHandle类的API，从系统中临时文件的默认存储位置读取了一个名为C11Example.txt的文件；
      （Code_使用NSFileHandle类读取文件）
     */
    NSString * tmpDir = NSTemporaryDirectory();
    NSString * myFile = [NSString stringWithFormat:@"%@/%@",tmpDir,@"C11Example.txt"];
    NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:myFile];
    if (fileHandle) {
        NSData * fileData = [fileHandle readDataToEndOfFile];
        NSLog(@"%lu bytes read from file %@",(unsigned long)[fileData length],myFile);
    }
    
     /*
      
     NSFileManager类：
        提供了执行基础文件系统操作的通用方法，这些操作包括创建文件管理器、查找目录、查询目录内容、管理文件和目录项、创建指向文件的软/硬链接、查询文件访问操作、获取/设置文件的系统属性以及管理iCloud存储项；
      （Code_使用NSFIleManager类查看当前目录内容）
      */
    NSFileManager * filemgr = [NSFileManager defaultManager];
    NSString * currentPath = [filemgr currentDirectoryPath];
    NSArray * contents = [filemgr contentsOfDirectoryAtPath:currentPath error:&error];
    NSLog(@"Contents:%@",contents);
    
    if (contents) {
        //检查一个文件是不是可执行文件
        NSString * file = [NSString stringWithFormat:@"%@/%@",currentPath,contents[0]];
        if ([filemgr isExecutableFileAtPath:file]) {
            NSLog(@"%@ is executable",file);
        }
    }
    
      /*
       log：
       2017-12-25 15:02:11.932055+0800 精通Objective-C[22782:8071899] Contents:(
       ".HFS+ Private Directory Data
       ",
       home,
       usr,
       ".Spotlight-V100",
       net,
       ".DS_Store",
       ".PKInstallSandboxManager",
       ".PKInstallSandboxManager-SystemSoftware",
       bin,
       "installer.failurerequests",
       Network,
       sbin,
       ".file",
       etc,
       "User Information",
       var,
       Library,
       ".Trashes",
       System,
       ".fseventsd",
       private,
       ".DocumentRevisions-V100",
       ".vol",
       Users,
       Applications,
       dev,
       Volumes,
       tmp,
       cores
       )
       2017-12-25 15:02:43.526661+0800 精通Objective-C[22782:8071899] //.HFS+ Private Directory Data
       is executable
       
     11.4.3 数据流的输入输出
       
     数据流：
        是一种用于连续读取和写入数据的方便机制，无论数据是在内存中、文件中还是在网络上；
       
     NSStream、NSInputStream和NSOutputStream类提供了从数据流读取数据和将数据写入数据流的功能；
       NSStream是一个抽象类；
       NSInputStream和NSOutputStream类是其具体子类；
       
     数据流可以通过轮询操作，以异步的方式（通常为首选方式）或同步方式被读取和写入；
        要通过异步方式访问数据流：
            必须为数据流设置委托对象（及NSInputStream对象或NSOutputStream对象）；
            并将数据流安排到运行循环中；
       
        该委托对象必须遵守NSStreamDelegate协议；
            运行循环会调用该对象中的stream：handleEvent：方法处理数据流事件（状态、可用数据和错误条件）；

     示例：通过一个文件创建输入数据流，然后以同步方式从指定文件读取数据并将这些数据写入缓冲区；
       （Code_NSInputStream类读取文件）
       */
    NSString * currentPath1 = [[NSFileManager defaultManager] currentDirectoryPath];
    NSString * myFile1 = [NSString stringWithFormat:@"%@/%@",currentPath1,@"C11Example.txt"];
    NSInputStream * ins = [NSInputStream inputStreamWithFileAtPath:myFile1];
    [ins open];
    if (ins && [ins hasBytesAvailable]) {
        uint8_t buffer[1024];
        NSUInteger len = [ins read:buffer maxLength:1024];
        NSLog(@"Bytes read = %lu",len);
    }
    
     /*
      分析：
        创建了输入数据流后，这段代码打开了该数据流；
        使用NSInputStream类的hasBytesAvailable方法判断该数据流中是否含有可读取的字节；
        有的话，则使用read方法将这些数据读取到缓冲区；
        最后将读取的字节数记录到控制台；
      
      
     11.4.4 元数据查询
      
     NSMetadataItem系列类和NSMetadataQuery系列类：
        提供了多个用于查询元数据的API，程序使用这些API可以根据文件或文件系统中的部分数据搜索文件；
        像苹果的桌面搜索工具Spotlight一样，这些类一起提供了以编程方式使用文件元数据执行文件搜索的方法；
        （只能在OS X上使用）
      
      =====================
      
     11.5 并发机制和线程
      
     使用支持并发机制和线程的类可以实现管理线程的功能，以及通过线程并行执行多个代码块的功能；
      
     接下来介绍这些类，第17章还会详细介绍OC平台的并行编程方法；
      
     11.5.1 线程管理
      
     NSTask类和NSThread类：
        用于管理线程和进程；
      
     使用NSTask类可以在OC运行时系统中创建和管理进程；
        NSTask实例作为独立进程进行操作，它不与其他进程共享内存；包括创建它的进程；
        一个NSTask对象只能运行一次，而且其环境需要在它运行之前配置好；
        比如：
            我们使用下述方法，创建和启动一个任务，执行当前目录中名为greeting的程序；
            NSTask * task = [NSTask launchTaskWithLaunchPath:@"./greeting" argments:nil];//OS X
        也可以：
            NSTask * hello = [[NSTask alloc] init];
            [hello setLaunchPath:@"./greeting"];
            [hello launch];
        可以使用isRunning方法查询任务状态；
      
      
     线程是一种操作系统机制，用于以并行的方式执行多个指令序列；
        线程通常被实现为轻量级进程，因为同一个进程中可以同时存在多个线程；
        同一个进程中的线程可以共享计算机中的内存和其他资源；
      
     使用NSThread类可以创建和控制线程；
        这个类中有很多方法，这些方法可以用来创建和初始化NSThread对象、启动和停止线程、配置线程以及查询线程及其执行环境；
        使用NSThread的detachThreadSelector：toTarget：withObject：方法，可以创建和启动新线程；
        使用setThreadPriority可以设置线程的优先权；（1.0为最高等级优先权）
        使用cancel方法可以向线程发送取消信号；
      */
    [NSThread detachNewThreadSelector:@selector(testCurrentTargetSEL) toTarget:self withObject:nil];//创建并执行（无法获取）
    
    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(testCurrentTargetSEL) object:nil];//创建获取 手动启动
    [thread setThreadPriority:1.0];
    [thread start];
    [thread cancel];
     /*
      log:
      2017-12-25 16:24:59.920413+0800 精通Objective-C[23587:8140370] Thead operation doing

     11.5.2 并行操作
      
     NSOperation、NSBlockOperation和NSInvocationOperation类：
        用于管理一个或多个操作、代码以及单独任务关联数据的并行执行过程；
     
     操作队列：
        是指提供并行执行任务功能的OC对象；
        每个任务（即操作）都定义了需要执行的程序和与之相关的数据；而且会被封装在块对象或NSOperation类的具体子类中；
      
     NSOperation是一个抽象类，用于封装单个任务的代码和相关数据；
        在处理非并行任务时，具体子类通常只需要重写主要方法；
        在处理并行任务时，至少必须重写start、isConcurrent、isExecuting和isFinished方法；
      
     使用NSOperationQueue类可以通过队列系统控制NSOperation对象的执行；
        操作队列会使用线程执行操作；（这类实现细节是隐式的）
        如[NSOperationQueue mainQueue];
        可以通过addOperation：来添加操作；
      
     11.5.3 锁定
      
     使用NSLock、NSDistributedLock、NSConditionLock和NSRecursiveLock类可以为同步执行的代码创建锁；
        NSLock类为并行编程方式实现了一个基本的互斥锁；（互斥锁）
        该类遵守NSLocking协议，因此实现了用于获取和释放锁的lock方法和unlock方法；
      
     NSDistributedLock类：（分布锁）
        定义了可由多台主机上的多个应用程序使用的锁，该锁可以控制对共享资源的访问；
      
     NSConditionLock类：（条件锁）
        定义了只能在特定条件下获取和释放的锁；
      
     NSRecursiveLock类：（递归所）
        定义了在不导致死锁的前提下，可由同一线程使用多次的锁；
        该锁会记录自身被使用的次数，在释放该锁前必须先调用对应的方法解锁对象，以实现所定和解锁操作的平衡；
      
     11.5.4 计时器和运行循环
      
     运行循环：
        是一种基于线程的机制；用于调度任务和协调收到的输入事件；
      
        如果程序的线程 需要回应 入站事件，就必须将之附到运行循环中，以在新事件出现时唤醒该线程；
      
     ios的UIApplication类的run方法，可以将应用程序的主循环添加到标准启动序列中，因此，使用xcode模板创建的程序，通常无需编写运行循环代码；
     其他情况下，如创建命令行程序，如果你编写的程序需要回应来自输入资源的事件，就需要编写运行循环代码；
      
     Foundation框架提供很多异步输入功能的类（如网络、数据流I/O），应该在程序中将这些类与运行循环结合起来使用；
      
     NSRunLoop类：
        提供了管理运行循环的API；
        这个类含有很多方法，使用它们可以访问运行循环和模式、管理计时器和端口、运行某个循环和管理消息；
        使用currentRunLoop方法可以获取当前的运行循环（代表当前线程的NSRunLoop对象）；
            如果线程的运行循环还不存在，该方法可以创建运行循环，并返回它；
      
     运行模式：为运行循环定义了输入源；
        Foundation框架定义了一系列用于设置可用运行循环模式的常数；
        常数NSDefaultRunLoopMode是最常用的运行循环模式；
      
     多种NSRunLoop方法运行循环；
        使用run方法可以将线程添加到NSDefaultRunLoopMode实例的永久循环中，然后线程就可以在NSDefaultRunLoopMode实例的生命周期中处理所有来自输入源的事件；
        如果要使用能够停止的循环，就不应该使用该方法，可以使用根据收到的输入信息或指定的时间运行相应循环的方法；
            使用runModel：beforeData：方法可以在NSDefaultRunLoopMode实例中运行一次循环，在从输入源收到时间和beforeDate：参数设置的时间点之前，不接受输入信息；
      
        示例：线程会一直等待所需输入的信息；
      */
    NSRunLoop * loop = [NSRunLoop currentRunLoop];
    [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

    /*
     如果[NSDate distantFuture]中的日期参数值为无穷大，线程就会一直等待所需输入的信息；
     
     NSTimer类：
        用于在经过了指定的时间后，向目标对象发送消息；
        将它的实例与NSRunLoop实例一起使用，可以通过同步的方式向线程发送事件；
        使用NSTimer实例可以设置运行循环对象等到输入的最长时间；
     
     使用NSTimer类的方法可以创建和初始化计时器、启动计时器、停止计时器和获取计时器信息；
        使用[NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) invocation:(nonnull NSInvocation *) repeats:(BOOL)];方法可以创建经过指定时间后取消的计时器；
        该计时器可用于调用消息设置时间间隔，并且可以在有需要时重复计时；
        使用invalidate方法可以是计时器不再启动；
        isValid方法能够返回表明当前计时器是否合法的布尔值；
     
     说了这么多，接下来实践一下；
      
     11.5.5 创建Bonjour网络服务客户端
     
     接下来将编写一个使用Bonjour网络服务API和运行循环的程序；
        该程序会创建一个服务端浏览器，后者会以异步方式查找指定类型的已注册服务；
     
     我们新建一个命令行应用程序命名为C11BonjourClient；
        接下来在工程目录中创建一个使用加载URL的API下载URL资源的类：C11BonjourClient类；
        更新相关代码如下：
     （Code C11BonjourClient.h C11BonjourClient.m）
     注意以下代码是在单独的一个工程中的；
     
     分析：
        C11BonjourClient类的接口采用NSNetServiceBrowserDelegate协议，因此会通过异步的方式从NSNetServiceBrowser实例加载数据；
        属性serverBrowser属性就是NSNetServiceBrowserDelegate实例；
        finishedLoading属性用于指明NSNetServiceBrowser实例完成数据加载的时间；
     
        当服务浏览器实例开始搜索服务时，会调用相应的回调方法；
     
     编写好了C11BonjourClient类，接下来我们通过Bonjour协议使用该类搜索已注册的服务；
        更新该工程的main函数中代码如下：
     （Code main.m）
     
     表达式[loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]会执行一次运行循环，阻止从输入源接收其他信息；
        接收信息后，该消息会在当前线程（即被调用的相应委托方法）中被处理，而且循环会再次开始运行；
        因此在设置finishedLoading之前，不会退出while循环；
     
     这个练习展示了如何编写一个使用Foundation框架API以异步的方式寻找已注册服务的程序；
     这个程序并不完整，已注册服务可以自行实现类进行测试，书中内容至此结束，待后续可查找资料（https://code.tutsplus.com/tutorials/creating-a-game-with-bonjour-client-and-server-setup--mobile-16233）补充实现，进行测试；
     
     ========
     
     11.6 URL处理
     
     URL处理类用于通过标准Internet协议（ftp、http、https和本地文件），与URL进行交互和与数据资源进行通信；
     这些类提供了下列功能：
     1）URL加载；
     2）缓存管理；
     3）身份验证和证书管理；
     4）Cookie管理；
     5）协议支持；
     
     这些类还支持代理服务器和每个用户的系统首选项安全套接字（SOCKS）网关；
     
     11.6.1 URL加载
     
     NSURL类：
        NSURL对象用于管理URL和URL引用的资源；
        NSURL类的方法可以用来创建和初始化NSURL对象、查询URL以及访问URL组件（即主机和端口等）；
        NSURL类还提供了用于处理书签数据的方法；
     
     书签：
        是指对文件位置的永久引用；它是一种宝贵的文件定位工具，因为即使在文件被移动或重命名的情况下，也可以使用它重建文件的URL；
     */
    NSURL * url = [NSURL URLWithString:@"http://www.apress.com:80"];
    NSLog(@"URL: scheme %@,host %@,port %@",url.scheme,url.host,url.port);
     
    /*
     log:
     2017-12-26 10:53:01.911834+0800 精通Objective-C[26601:8389700] URL: scheme http,host www.apress.com,port 80

     NSURLRequest类和NSMutableURLRequest类：
        用于代表URL加载请求；
        NSURLRequest类：
            是一个独立的网络协议和URL方案；
            使用其方法可以创建和初始化URL请求以及获取请求的属性；
        NSMutableURLRequest类是NSURLRequest类的子类：
            使用其方法可以更改URL及其组件；
        示例：创建一个可变URL请求，然后设置该HTTP请求的方法值；
     */
    NSMutableURLRequest * req = [NSMutableURLRequest requestWithURL:url];
    [req setHTTPMethod:@"GET"];
    /*
     
     NSURLResponse类和NSHTTPURLResponse类：
        用于代表URL请求反应的回应；
        NSURLResponse对象可以有执行URL请求的同步加载操作（sendSynchronousRequest：returningResponse：error：）的对象创建；
            也可以由遵守NSURLConnectionDataDelegate协议的对象创建；
        NSHTTPURLResponse是NSURLResponse类的子类：
            使用其方法可以访问由URL请求返回的HTTP特定信息；
     
     NSUELConnection类和NSURLDownload类：
        用于下载通过URL识别的资源；
        NSUELConnection类支持同步和异步方式的资源加载、开始和停止连接，以及管理用于控制URL连接各个方面（即缓存管理、身份认证和证书、协议支持和Cookie的管理）的委托对象；
     
     在使用异步加载资源时必须设置委托对象：
        该对象遵循NSURLConnectionDelegate协议，至少会实现如下方法：
     1）connection：didReceiveData：（获取被加载的数据）
     2）connection：didFailWithError：（处理链接错误）
     3）connection：didFinishLoading：（加载数据操作完成）
     
     示例：使用NSURLConnection类以同步的方式加载URL的内容：
     */
    NSURL * url1 = [NSURL URLWithString:@"http://www.apress.com/index.html"];
    NSURLRequest * request1 = [NSURLRequest requestWithURL:url1];
    NSURLResponse * response1;
    NSError * aerror1;
    NSData * data1 = [NSURLConnection sendSynchronousRequest:request1 returningResponse:&response1 error:&aerror1];
    NSLog(@"Expected content length = %lld,loaded %lu bytes",[response1 expectedContentLength],[data1 length]);
    
    /*
     log:
     2017-12-26 11:25:39.451971+0800 精通Objective-C[26911:8415701] Expected content length = -1,loaded 11941 bytes

     注：ios9之后 推荐使用NSURLSession类；
     
     NSURLDownload类：
        用于通过异步方式，将URL的内容下载到文件中；
        使用其方法可以初始化下载操作（设置请求和委托对象）、设置目标路径、重新开始未完成的下载操作和取消下载请求；
        NSURLDownload类还提供了对MacBinary、BinHex和gzip格式文件的支持；
        其委托对象必须遵守NSURLDownloadDelegate协议，因而会至少实现下列方法：
        1）download：didFailWithError：（处理链接错误）
        2）downloadDidFinish：（加载数据完成后，执行处理操作）
     
     注：这个类只能在Max OX上使用，现在的话 推荐使用NSURLSessionDownloadTask类，可自行查阅API；
     
     11.6.2 缓存管理
     
     缓存管理类（NSURLCache和NSCachedURLResponse）为对URL请求的回应提供了缓存；
        NSURLCache类为NSURL提供了通用缓存；
        NSCachedURLResponse类用于封装URL回应（即NSURLResponse对象）和通用URL加载的数据（即NSData对象）；
     
     NSURLConnection委托对象必须实现connection：willCacheResponse：方法，提供由NSURLCache实例初始化的NSCachedURLResponse对象，以便管理缓存
     
     接下里，我们将编写一个用URL加载类下载资源的程序；
     
     11.6.3 使用URL加载API下载资源
     
     下面编写使用URL加载API下载URL资源的类：C11NetConnector;
     （Code C11NetConnector.h C11NetConnector.m）
     
     我们来详细看一下这段代码：
     1）使用分类声明了C11NetConnector类的实现代码中使用的私有属性；
        C11NetConnector的实现代码定义了接口声明的方法和NSURLConnectionDataDelegate协议声明方法；
        init方法中，为了缓存回应，创建并初始化了一个NSURLCache实例；
            创建缓存，并使用内存存储结构配置了该缓存，然后将其设置为与连接一起使用的共享缓存；
        最后创建了一个NSURLConnection对象并开始下载URL；
     2）其余代理方法，我们在代码中做了注释；
     
     编写好这个类之后，我们来使用它加载一个URL；
     */
    NSString * index_url = @"http://www.wikipedia.com/index.html";
    
    //获取当前的运行循环
    NSRunLoop * runloop = [NSRunLoop currentRunLoop];
    
    //使用指定的缓存策略来创建请求，然后开始下载
    NSURLRequest * request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:index_url] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:5];
    
    C11NetConnector * netConnect = [[C11NetConnector alloc] initWithRequest:request2];
    //一直循环 知道加载资源操作结束为止
    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
    }
    
    //记录缓存占用内存大小
    NSLog(@"Cache memory usage = %lu bytes",[[NSURLCache sharedURLCache] currentMemoryUsage]);
    
    //通过请求重新加载数据，这次会从缓存获取数据
    [netConnect reloadRequest];
    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
        //运行循环，直到netConnect.finishedLoading == YES；
    }
    //释放缓存
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    /*
     log:
     2017-12-26 16:05:35.861566+0800 精通Objective-C[29350:8632734] Downloaded data,caching response
     2017-12-26 16:05:35.861917+0800 精通Objective-C[29350:8632734] Download 1242 bytes from request <NSURLRequest: 0x60c000012d70> { URL: http://www.wikipedia.com/index.html }
     2017-12-26 16:05:35.862149+0800 精通Objective-C[29350:8632734] Cache memory usage = 1242 bytes
     2017-12-26 16:05:36.059240+0800 精通Objective-C[29350:8632734] Download 1242 bytes from request <NSURLRequest: 0x60c000012d70> { URL: http://www.wikipedia.com/index.html }
     
     分析：
     1）NSURLRequestReturnCacheDataElseLoad对应的缓存策略设置了只有在cache中不存在data时才从原始地址下载；
        注意，如果某个url不支持缓存策略，即便设置了也是无效的；
     2）    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
        这段代码可能会觉得熟悉，是的我们之前用过：
            这段代码会运行循环，从输入源接收事件并执行相应的委托方法，直到连接完成加载资源的操作为止；
     3）我们将缓存使用情况打印出来；
        重新请求时，因为数据已经被存储在缓存中，而且缓存策略设置了应使用的缓存大小，所以无须从URL加载数据就可以立即得到数据；
            从缓存中获取数据，connection: willCacheResponse:委托方法将不会被调用；
     4）最后释放缓存；
     
     这个程序实践了使用URL加载API，通过异步方式下载URL的知识；
     
     备注：
     1.NSURLRequestUseProtocolCachePolicy NSURLRequest   默认的cache policy，使用Protocol协议定义。
     2.NSURLRequestReloadIgnoringCacheData               忽略缓存直接从原始地址下载。
     3.NSURLRequestReturnCacheDataDontLoad               只使用cache数据，如果不存在cache，请求失败；用于没有建立网络连接离线模式
     4.NSURLRequestReturnCacheDataElseLoad               只有在cache中不存在data时才从原始地址下载。
     5.NSURLRequestReloadIgnoringLocalAndRemoteCacheData 忽略本地和远程的缓存数据，直接从原始地址下载，与NSURLRequestReloadIgnoringCacheData类似。
     6.NSURLRequestReloadRevalidatingCacheData           验证本地数据与远程数据是否相同，如果不同则下载远程数据，否则使用本地数据
     
     下面介绍下载资源是解决身份验证的手段；
     
     11.6.4 身份认证和证书管理
     
     身份认证和证书管理类：
        NSURLProtectionSpace、NSURLCredentialStorage、NSURLCredential、NSURLAuthenticationChallenge和NSURLAuthenticationChallengeSender；
        提供了对请求访问受保护URL的用户进行身份认证；
        需要身份认证的资源要求 尝试加载资源的客户端提供证书；
     
     Foundation框架的NSURLAuthenticationChallenge类封装了从客户端向服务端提供认证请求的功能；
     NSURLCredential类代表为了回应身份认证要求，用户返回的证书；
     
     当连接请求要求进行身份认证时，NSURLConnection和NSURLDownload实例的委托协议就是被发送的消息；
        这样就会实现相应的方法，返回正确的证书；
     
     对于NSURLConnectionDelegate协议来说：
        应实现connection：willSendRequestForAuthenticationChallenge：方法；
        我们可以为C11NetConnector类实现这个方法；
     （Code）
     -(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
        //使用用户名 密码 创建了一个证书
        NSURLCredential * credential = [NSURLCredential credentialWithUser:@"TestUser" password:@"TestPassword" persistence:NSURLCredentialPersistenceForSession];
        //使用证书回应连接的身份认证质询
        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
     }
     
     11.6.5 Cookie管理
     
     使用Foundation框架的NSHTTPCookie和NSHTTPCookieStorage类可以创建和管理HTTP Cookie；
        这类Cookie用于永久存储跨URL请求的数据；
        一个NSHTTPCookie实例就代表一个Cookie；
        NSHTTPCookieStorage是一个单例对象，用于管理Cookie；
     
     对于OS X Cookie是公用的，并且由多个进程以同步方式访问；
     对于单个进程来说，会话Cookie是局部的；不会与其他程序共享；
     
     NSHTTPCookie提供的方法：
        可以创建Cookie、将Cookie转换为请求的报头和 获取Cookie属性；
     
     NSHTTPCookieStorage提供的方法：
        使用可以回去公用Cookie的存储实例、管理Cookie接受策略和管理（即添加、删除和获取）Cookie；
     
     11.6.6 协议支持
     
     使用Foundation框架的NSURLProtocol类和NSURLProtocolClient类；
        可以从url加载数据创建自定义协议；
        NSURLProtocol类：
            是一个抽象类，提供了执行协议特定URL加载的基础结构；
            使用其方法可以创建NSURLProtocol对象、注册协议类和取消协议类的注册、管理请求、获取协议特性以及开始和停止下载操作；
        NSURLProtocolClient类：
            是一个由NSURLProtocol类的子类使用的协议，用于与URL加载系统通信；
     
     
     11.7 进程间通信
     
     Foundation框架提供了许多用于进程间通信的类；
        尤其可以创建和使用通信信道；
     
     11.7.1 通过信道通信
     
     NSPipe类可以封装管道（pipe）；
        管道是用于在进程间进行通信的单向信道；
        使用其方法可以创建和初始化管道，以及获取管道的想用NSFileHandle实例；
     
     NSTask类（进程）提供了两个方法：
        setStandardOutput：和setStandardInput：，用于设置进程的输入和输出信道；
     
     示例：使用NSPipe和NSTask类，创建并启动一个任务，设置标准输出，然后在任务完成后获取该标准输出并将之写入信道
     （Unix命令/bin/ls仅用于列出当前目录中的文件）
     （Code_11.7.1）
     NSTask * task = [[NSTask alloc] init];
     [task setLaunchPath:@"/bin/ls"];
     NSPipe * outPipe = [NSPipe pipe];
     [task setStandardOutput:outPipe];
     [task launch];
     NSData * output = [[outPipe fileHandleForReading] readDataToEndOfFile];
     NSString * lsout = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
     NSLog(@"/bin/ls output:\n%@",lsout);
     
     log:(由于这个类只能在OS X上使用，所以我们在C11BonjourClient工程中的main函数中，实现如上测试代码)
     C11BonjourClient[30348:9164991] /bin/ls output:
     C11BonjourClient
     
     11.7.2 通过端口通信
     
     NSPort、NSMachPort、MSMessagePort和NSSocketPort类：
        为进程和线程间通信提供了底层机制（通常通过NSPortMessage对象）；
     
     NSPort类：
        是一个抽象类；使用其方法可以创建和初始化端口、创建端口连接、设置端口信息和监听端口；
     
     NSMachPort、MSMessagePort和NSSocketPort类：
        是NSPort类的具体子类，用于设置通信端口的类型；
        NSMachPort、MSMessagePort类：
            仅允许进行本地通信（即在同一台设备上）；
            此外，NSMachPort类用于Mach端口（OS X中的基础通信端口）；
        NSSocketPort类：
            即允许进行本地通信，也允许进行远程通信；（用作本地通信时效率不如专门用于本地通信的类）
     
     在创建NSConnection实例时（使用initWithReceivePort：sendPort：方法），可以将端口实例用作参数；
     还可以通过NSPort类的scheduleInRunLoop：forMode：方法，向运行循环中添加端口；
     
     因为端口是底层的进程间通信机制，所以在实现应用通信时，应在尽可能地使用分布式对象，而只在必要时使用NSPort对象；
     结束对端口对象的操作后，必须使用NSPort类的invalidate方法显示地使对象失效；
     
     11.7.3 端口注册
     
     NSPortNameServer、NSMachBootstrapServer、NSMessagePortNameServer和NSSocketPortNameServer类为端口注册服务提供了接口；
        使用它们可以获取NSMachPort、NSMessagePort和NSSocketPort实例；
     
     NSPortNameServer类为分布式对象系统使用的端口注册服务提供了面向对象的接口；
        NSConnection对象使用该接口相互联系，并将对象分发到网络中；
        直接通过NSPortNameServer实例进行交互的情况极少见；
     
     NSMachBootstrapServer、NSMessagePortNameServer和NSSocketPortNameServer类：
        是NSPortNameServer类的子类；
        它们可以返回相应的端口实例（NSMachPort、MSMessagePort和NSSocketPort）；
     
     11.8 小结
     
     本章介绍Foundation框架，专注于为大多数OC程序提供通用功能的类；
     现在熟悉这些类提供的如下功能即可：
     1）网络服务；
     2）应用服务；
     3）文件系统服务；
     4）URL处理；
     5）进程间通信；
     6）并发机制和线程；
     
     */
    
}
-(void)testCurrentTargetSEL{
    NSLog(@"Thead operation doing");
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
